#include "perspective_camera.h"

PerspectiveCamera::PerspectiveCamera(Scene* scene, Output* output, const Vector3& p, 
		const Vector3& d, const Vector3& u, float fov) 
		: Camera(scene, output), pos(p), dir(d), up(u), fov(fov)
{
	// Points lying on exact middles of screen plane vertical sides
	Vector3 l, r;
	l = Vector3::cross(dir, up);
	r = Vector3::cross(dir * -1.0f, up);

	l.normalize();
	r.normalize();

	// Half width of screen plane
	float half_width = dir.length() / tan(fov);

	l *= half_width;
	r *= half_width;

	// Screen aspect ratio
	float aspect = float(output->width) / float(output->height);

	// Height of screen plane;
	float height = 2.0 * half_width / aspect;

	Vector3 norm_up = up;
	norm_up.normalize();

	// Four corner points of screen plane
	tl = pos + dir + l + (norm_up * (height / 2.0));
	bl = pos + dir + l - (norm_up * (height / 2.0));
	tr = pos + dir + r + (norm_up * (height / 2.0));
	br = pos + dir + r - (norm_up * (height / 2.0));
}

void PerspectiveCamera::raytrace()
{
	output->init();

	// Interpolation coefficients
	float tx, ty;

	for(int y = 0; y < output->height; ++y)
	{
		ty = float(y) / float(output->height);
		for(int x = 0; x < output->width; ++x)
		{
			tx = float(x) / float(output->width);
			
			// Compute ray direction by lerping 
			// between 4 corners of screen plane
			Vector3 t = lerp(tl, tr, tx);
			Vector3 b = lerp(bl, br, tx);
			Vector3 target = lerp(t, b, ty);

			Ray ray(pos, target - pos);
			Color c = scene->trace(ray);

			output->set_pixel(x, y, c);
		}
	}

	output->close();
}

